package com.googlecode.adaboost.classifier.util;

import com.googlecode.adaboost.classifier.BinaryWeakClassifier;
import com.googlecode.adaboost.classifier.RealWeakClassifier;
import com.googlecode.adaboost.trainer.TrainingData;

public class WeakClassifierEvaluator {
	/**
	 * 
	 * @param classifier
	 * @param trainingData
	 * @param probability
	 * @return errorRate of the classifier, this function also set the value of
	 *         alpha in the classifier
	 */
	public static double evaluateBinaryClassifier(
			BinaryWeakClassifier classifier, TrainingData trainingData,
			double[] probability) {
		double errorRate = 0.0;
		for (int i = 0; i < trainingData.getDataNum(); ++i) {
			if (classifier.makeDecision(trainingData.getTrainingData().get(i)) != trainingData
					.getTrainingData().get(i).getOutput()) {
				errorRate += probability[i];
			}
		}
		classifier.setAlpha(0.5 * Math.log(1 / errorRate - 1));
		return errorRate;
	}

	/**
	 * 
	 * @param classifier
	 * @param trainingData
	 * @param probability
	 * @param epsilon
	 * @return errorRate of the classifier, this function also set the values of
	 *         cplus and cminus in the classifier
	 */
	public static double evaluateRealClassifier(RealWeakClassifier classifier,
			TrainingData trainingData, double[] probability, double epsilon) {
		double G = 0.0;
		double[] P = new double[4];
		for (int i = 0; i < trainingData.getDataNum(); ++i) {
			if (classifier.makeDecision(trainingData.getTrainingData().get(i)) == trainingData
					.getTrainingData().get(i).getOutput()) {
				if (trainingData.getTrainingData().get(i).getOutput() == 1) {
					P[0] += probability[i];
				} else {
					P[1] += probability[i];
				}
			} else {
				if (trainingData.getTrainingData().get(i).getOutput() == 1) {
					P[2] += probability[i];
				} else {
					P[3] += probability[i];
				}
			}
		}
		G = Math.sqrt(P[0] * P[3]) + Math.sqrt(P[2] * P[1]);
		classifier
				.setCplus(0.5 * Math.log((P[0] + epsilon) / (P[3] + epsilon)));
		classifier.setCminus(0.5 * Math
				.log((P[2] + epsilon) / (P[1] + epsilon)));
		return G;
	}
}
